package cn.jbt.api.admin.service.impl;

import cn.jbt.api.admin.entity.QSysRegion;
import cn.jbt.api.admin.entity.SysRegion;
import cn.jbt.api.admin.repository.SysRegionRepository;
import cn.jbt.api.admin.service.ISysRegionService;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
@AllArgsConstructor
public class SysRegionServiceImpl implements ISysRegionService {

    private final SysRegionRepository sysRegionRepository;
    private final JPAQueryFactory jpaQueryFactory;

    @Override
    public List<SysRegion> getAll(SysRegion sysRegion) {

        QSysRegion qSysRegion = QSysRegion.sysRegion;

        Predicate predicate = qSysRegion.isNotNull().or(qSysRegion.isNull());
        if (null != sysRegion) {
            if (!StringUtils.isEmpty(sysRegion.getName())) {
                predicate = ExpressionUtils.and(predicate,
                        qSysRegion.name.contains(sysRegion.getName()));
            }
            if (null != sysRegion.getStatus()) {
                predicate = ExpressionUtils.and(predicate,
                        qSysRegion.status.eq(sysRegion.getStatus()));
            }
        }

        return jpaQueryFactory.selectFrom(qSysRegion)
                .where(predicate)
                .orderBy(qSysRegion.orderby.asc(), qSysRegion.level.asc(), qSysRegion.id.asc())
                .fetch();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public SysRegion add(SysRegion sysRegion) {

        sysRegion = sysRegionRepository.save(sysRegion);

        // update level、path
        if (sysRegion.getPid() > 0) {
            SysRegion parent = sysRegionRepository.findFirstById(sysRegion.getPid());
            if (null == parent) {
                throw new RuntimeException("父级未找到");
            }
            sysRegion.setLevel(parent.getLevel() + 1);
            sysRegion.setPath(parent.getPath() + sysRegion.getId() + "/");
        } else {
            sysRegion.setLevel(1);
            sysRegion.setPath(sysRegion.getId() + "/");
        }

        return sysRegionRepository.save(sysRegion);
    }

    @Override
    public SysRegion edit(SysRegion sysRegion) {
        SysRegion newSysRegion = sysRegionRepository.findFirstById(sysRegion.getId());
        if (null == newSysRegion) {
            throw new RuntimeException("404 NotFound");
        }

        newSysRegion.edit(sysRegion);
        return sysRegionRepository.save(newSysRegion);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void del(List<Long> ids) {
        for (Long id : ids) {
            SysRegion child = sysRegionRepository.findFirstByPid(id);
            if (null != child) {
                throw new RuntimeException("请先删除下级");
            }

            sysRegionRepository.deleteById(id);
        }
    }

    @Override
    public String getCascadeNamesById(long id, String delimiter) {

        SysRegion sysRegion = sysRegionRepository.findFirstById(id);
        if (null == sysRegion) {
            return "";
        }

        List<Long> ids = Arrays.stream(sysRegion.getPath().split("/"))
                .filter(StringUtils::isNotEmpty)
                .map(Long::parseLong)
                .toList();

        QSysRegion qSysRegion = QSysRegion.sysRegion;
        List<String> names = jpaQueryFactory.select(qSysRegion.name)
                .from(qSysRegion)
                .where(qSysRegion.id.in(ids))
                .orderBy(qSysRegion.level.asc())
                .fetch();

        return String.join(delimiter, names);
    }
}
